package com.choosefine.base.shixiaobao.common.exception;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import com.choosefine.base.shixiaobao.base.BaseController;
import com.choosefine.base.shixiaobao.common.def.ResultCode;
import com.choosefine.base.shixiaobao.common.exception.handle.ArgumentResultHandle;
import com.google.gson.Gson;

/**
 * 全局异常捕获
 * 
 * Author：liaozhanggen
 * Create Date：2017年3月24日
 * Version：v2.0
 */
@ControllerAdvice
@ResponseBody
public class GlobalDefaultExceptionHandler extends BaseController {
	Logger logger = LoggerFactory.getLogger(GlobalDefaultExceptionHandler.class);

	/**
	 * 异常跳转捕获
	 */
	// @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)//500处理
	@ExceptionHandler(value = { Exception.class})
	public String defaultExceptionHandler(HttpServletRequest req, Exception e) {
		logger.error("------------defaultExceptionHandler--------> " + e.getMessage());
		return responseFail(ResultCode.FAILED, e.getMessage());
	}

	/**
	 * 添加全局异常处理400流程，根据需要设置需要处理的异常，先处理MethodArgumentNotValidException
	 *
	 * @Author：liaozhanggen
	 * @Create Date：2017年3月24日 @param：....
	 * @return：Object
	 */
	// @ResponseStatus(HttpStatus.BAD_REQUEST)//400处理
	@ExceptionHandler(value = { MethodArgumentNotValidException.class})
	public String methodArgumentNotValidHandler(HttpServletRequest request, MethodArgumentNotValidException exception) {
		logger.error("------------methodArgumentNotValidHandler--------> " + exception.getMessage());
		// 按需重新封装需要返回的错误信息
		List<ArgumentResultHandle> arguments = new ArrayList<>();
		// 解析原错误信息，封装后返回，此处返回非法的字段名称，原始值，错误信息
		for (FieldError error : exception.getBindingResult().getFieldErrors()) {
			ArgumentResultHandle invalidArgument = new ArgumentResultHandle();
			invalidArgument.setMessage(error.getDefaultMessage());
			invalidArgument.setField(error.getField());
			invalidArgument.setValue(error.getRejectedValue());
			arguments.add(invalidArgument);
		}

		return responseFail(new Gson().toJson(arguments));
	}

	@ExceptionHandler(MissingServletRequestParameterException.class)
	public String missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException exception) {
		logger.error("------------missingServletRequestParameterExceptionHandler--------> " + exception.getMessage());
		return responseFail("缺少请求参数");
	}

	@ExceptionHandler(HttpMessageNotReadableException.class)
	public String httpMessageNotReadableExceptionHandler(HttpMessageNotReadableException exception) {
		logger.error("------------missingServletRequestParameterExceptionHandler--------> " + exception.getMessage());
		return responseFail("参数解析失败");
	}

	@ExceptionHandler(BindException.class)
	public String bindExceptionHandler(BindException e) {
		logger.error("------------bindExceptionHandler--------> " + e.getMessage());
		BindingResult result = e.getBindingResult();
		FieldError error = result.getFieldError();
		String field = error.getField();
		String code = error.getDefaultMessage();
		String message = String.format("%s:%s", field, code);
		return responseFail(message);
	}

	@ExceptionHandler(ConstraintViolationException.class)
	public String constraintViolationExceptionHandler(ConstraintViolationException e) {
		logger.error("参数验证失败 " + e.getMessage());
		Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
		ConstraintViolation<?> violation = violations.iterator().next();
		String message = violation.getMessage();

		return responseFail("parameter:" + message);
	}

	@ExceptionHandler(ValidationException.class)
	public String validationExceptionHandler(ValidationException e) {
		logger.error("参数验证失败 " + e.getMessage());
		return responseFail("参数验证失败 ");
	}

	/**
	 * 405 - Method Not Allowed
	 */
	@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
	@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
	public String httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e) {
		logger.error("不支持当前请求方法", e);
		return responseFail("参数验证失败 ");
	}

	/**
	   * 415 - Unsupported Media Type
	   */
	  @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
	  @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
	  public String handleHttpMediaTypeNotSupportedException(Exception e) {
	    logger.error("不支持当前媒体类型", e);
	    return responseFail("不支持当前媒体类型");
	  }
	  
	  /**
	   * 500/400 - Internal Server Error
	   */
//	  @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	  @ExceptionHandler(BusinessException.class)
	  public String handleServiceException(BusinessException e) {
	    logger.error("业务逻辑异常", e);
	    return responseFail("业务逻辑异常"+e.getMessage());
	  }

//	  /**
//	   * 500 - Internal Server Error
//	   */
//	  @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
//	  @ExceptionHandler(Exception.class)
//	  public String handleException(Exception e) {
//	    logger.error("通用异常", e);
//	    return responseFail("通用异常"+e.getMessage());
//	  }

	  /**
	   * 操作数据库出现异常:名称重复，外键关联
	   */
	  @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	  @ExceptionHandler(DataIntegrityViolationException.class)
	  public String handleException(DataIntegrityViolationException e) {
	    logger.error("操作数据库出现异常:", e);
	    return responseFail("操作数据库出现异常：字段重复、有外键关联等");
	  }

}
